
import java.applet.AudioClip;
import java.io.*;
import java.applet.Applet;
import java.net.MalformedURLException;
import java.net.URL;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.sound.sampled.*;
import javax.swing.*;
import java.net.*;
import java.math.*;
import javax.swing.event.MenuKeyListener;
import javax.swing.text.html.HTMLDocument;

class Point{
    int x,y;
    Point(int _x,int _y){
        this.x=_x;
        this.y=_y;
    }
    Boolean equals(Point a){
        if(a==null)
            return false;
        if(x==a.x&&y==a.y)
            return true;
        else
            return false;
    }
 }
public class RetroSnakes extends JComponent {
    Boolean keyactionBuffer=true;
    Socket socketClient=null;
    static JFrame app;
    static String serverIP="192.168.43.184";
    File f;
    FileWriter fw;
    Long millis=300l;//设置绘画刷新时间，即蛇前进速度
    Boolean startFlag=true;
    BufferedReader brInFromServer;
    static DataOutputStream dosOutToServer;
    LinkedList<Point> snakeA=new LinkedList<>();
    LinkedList<Point> snakeB=new LinkedList<>();
    ArrayList<Point> wall=new ArrayList<>();
    Point pointFoodA,pointFoodB;
    int scoreA=0,scoreB=0;
    JLabel As=new JLabel("0"),Bs=new JLabel("0");//动态记分框
    Random rd=new Random();
    char dirA='r';//运动方向
    char dirB;
    Iterator<Point> a;
    Boolean food;//判断食物是否全部存在
    RetroSnakes(){
        try{
            socketClient=new Socket(serverIP,10087);
            brInFromServer = new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
            dosOutToServer = new DataOutputStream(socketClient.getOutputStream());
            f=new File("record.txt");
        }
        catch(Exception e){e.printStackTrace();}
        setFocusable(true);
        initial();
        addScore();
        addKeyListener(new KeyAdapter(){
            public void keyPressed(KeyEvent e){
                super.keyPressed(e);
                switch(e.getKeyCode()){
                    case KeyEvent.VK_RIGHT:if(dirA!='l'&&keyactionBuffer)dirA='r';break;
                    case KeyEvent.VK_LEFT:if(dirA!='r'&&keyactionBuffer)dirA='l';break;
                    case KeyEvent.VK_UP:if(dirA!='d'&&keyactionBuffer)dirA='u';break;
                    case KeyEvent.VK_DOWN:if(dirA!='u'&&keyactionBuffer)dirA='d';break;
                }
                keyactionBuffer=false;
            }
        });
    }
    void initial(){
        scoreA=0;
        As.setText(""+scoreA);
        scoreB=0;
        As.setText(""+scoreB);
        createWall();
        createSnake(snakeA);
        createSnake(snakeB);
        createFood();
        dirA='r';
        dirB='l';
        Net();

    }
    void addScore(){    //添加记分板
        setLayout(new BorderLayout());
        JPanel bottom=new JPanel();
        bottom.setOpaque(false);
        JPanel Ascore=new JPanel();
        Ascore.setOpaque(false);
        JLabel A=new JLabel("A score:");
        Ascore.add(A);
        Ascore.add(As);
        JPanel Bscore=new JPanel();
        Bscore.setOpaque(false);
        JLabel B=new JLabel("B score:");
        Bscore.add(B);
        Bscore.add(Bs);
        bottom.add(Ascore);
        bottom.add(Bscore);
        add(bottom,"South");
    }
    void snakeMove(Point newHead,LinkedList<Point> snake){
        snake.addFirst(newHead);
        snake.pollLast();
    }
    void Net(){
        try{
            dosOutToServer=new DataOutputStream(socketClient.getOutputStream());
            dosOutToServer.writeBytes("initial\n");
            Iterator<Point> a=wall.listIterator();
            while(a.hasNext()) {
                Point temp=a.next();
                System.out.println("哈哈哈哈哈哈");
                dosOutToServer.writeBytes(""+temp.x+'\n');
                dosOutToServer.writeBytes(""+temp.y+'\n');
            }
            dosOutToServer.writeBytes("w\n");
            a=snakeA.listIterator();
            while(a.hasNext()) {
                Point temp=a.next();
                dosOutToServer.writeBytes(""+temp.x+'\n');
                dosOutToServer.writeBytes(""+temp.y+'\n');
            }
            dosOutToServer.writeBytes("A\n");
            a=snakeB.listIterator();
            while(a.hasNext()) {
                Point temp=a.next();
                dosOutToServer.writeBytes(""+temp.x+'\n');
                dosOutToServer.writeBytes(""+temp.y+'\n');
            }
            dosOutToServer.writeBytes("B\n");
            dosOutToServer.writeBytes(""+pointFoodA.x+'\n');
            dosOutToServer.writeBytes(""+pointFoodA.y+'\n');
            dosOutToServer.writeBytes(""+pointFoodB.x+'\n');
            dosOutToServer.writeBytes(""+pointFoodB.y+'\n');
            scoreA=0;
            scoreB=0;
        }
        catch(Exception f){
            f.printStackTrace();
        }
    }
    void Begin(){
        try {
            dosOutToServer.writeBytes("begin\n");
            a = snakeA.listIterator();
            while (a.hasNext()) {
                Point temp = a.next();
                dosOutToServer.writeBytes("" + temp.x + '\n');
                dosOutToServer.writeBytes("" + temp.y + '\n');
            }
            dosOutToServer.writeBytes("A\n");
            if (pointFoodA != null) {
                dosOutToServer.writeBytes("true\n");
                dosOutToServer.writeBytes("" + pointFoodA.x + '\n');
                dosOutToServer.writeBytes("" + pointFoodA.y + '\n');
            }
            else
                dosOutToServer.writeBytes("false\n");
            if (pointFoodB != null) {
                dosOutToServer.writeBytes("true\n");
                dosOutToServer.writeBytes("" + pointFoodB.x + '\n');
                dosOutToServer.writeBytes("" + pointFoodB.y + '\n');
            }
            else
                dosOutToServer.writeBytes("false\n");
            dosOutToServer.writeBytes("scoreA"+'\n');
            dosOutToServer.writeBytes(""+scoreA+'\n');
            dosOutToServer.writeBytes("scoreB"+'\n');
            dosOutToServer.writeBytes(""+scoreB+'\n');
            dosOutToServer.writeBytes("end\n");
            brInFromServer = new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
            String stringTemp=brInFromServer.readLine();
            System.out.println(stringTemp+'*');
            if(stringTemp.equals("forceS")) {
                startFlag = Boolean.valueOf(brInFromServer.readLine());
                brInFromServer.readLine();
            }
            else if(stringTemp.equals("forceM")) {
                millis = Long.valueOf(brInFromServer.readLine());
                brInFromServer.readLine();
            }
            if(stringTemp.equals("begin")){}
            snakeB.clear();
            while(true) {
                String temp=brInFromServer.readLine();
                if(temp.equals("1000")) {//1000为位置传输结束标识
                    pointFoodA=null;
                    break;
                }
                else if(temp.equals("1001")) {
                    pointFoodB=null;
                    break;
                }
                else if(temp.equals("1002")) {
                    break;
                }
                else if (temp!=null) {
                    System.out.println(temp);
                    String[] temps=temp.split(",");
                    System.out.println(temps[0]);
                    System.out.println(temps[1]);
                    Integer xTemp =  Integer.parseInt(temps[0]);
                    Integer yTemp =  Integer.parseInt(temps[1]);
                    Point tempPoint=new Point(xTemp,yTemp);
                    snakeB.add(tempPoint);
                }
        }}
        catch(Exception e){e.printStackTrace();}
    }
    void startGame() {
        class MyThread extends Thread {
            Point newHead;
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(millis);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Begin();
                    keyactionBuffer=true;
                    if(startFlag) {
                        switch (dirA) {
                            case 'r':
                                newHead = new Point(snakeA.get(0).x + 20, snakeA.get(0).y);
                                if (newHead.x > 600) newHead.x = 0;
                                break;
                            case 'l':
                                newHead = new Point(snakeA.get(0).x - 20, snakeA.get(0).y);
                                if (newHead.x < 0) newHead.x = 600;
                                break;
                            case 'u':
                                newHead = new Point(snakeA.get(0).x, snakeA.get(0).y - 20);
                                if (newHead.y < 0) newHead.y = 600;
                                break;
                            case 'd':
                                newHead = new Point(snakeA.get(0).x, snakeA.get(0).y + 20);
                                if (newHead.y > 600) newHead.y = 0;
                                break;
                        }
                        snakeMove(newHead, snakeA);
                        eatFoodA();
                        eatFoodB();
                        System.out.println("fsdfwerrfweref"+scoreB);
                        EatThread eatThread = new EatThread();
                        eatThread.start();
                        try {
                            fw=new FileWriter(f,true);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        PrintWriter pw=new PrintWriter(fw);
                        if (hitSnakeA() || hitWall(snakeA)) {
                            System.out.println("哈哈哈哈哈哈哈哈哈哈哈哈"+scoreA+','+scoreB);
                            pw=new PrintWriter(fw);
                            pw.println(Math.max(scoreA,scoreB));
                            pw.close();
                            initial();
                            recordSort();
                        }
                        else if (hitSnakeB() || hitWall(snakeB)) {
                            pw=new PrintWriter(fw);
                            pw.println(Math.max(scoreA,scoreB));
                            pw.close();
                            initial();
                            recordSort();
                        }
                        repaint();
                    }
                }
            }
        }
        MyThread moveThread = new MyThread();
        moveThread.start();
    }
    class EatThread extends Thread{
        public void run(){
                if(pointFoodA==null&&pointFoodB==null) {
                    try {
                        Thread.sleep(2000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    createFood();
                }
        }
    }
    void createWall(){
        wall.clear();
        for(int j=0;j<4;j++) {
            int wallX = rd.nextInt(519);
            wallX = wallX - wallX % 20;
            int wallY = rd.nextInt(519);
            wallY = wallY - wallY % 20;
            int num = rd.nextInt(6) + 7;
            if (j < 2)
                for (int i = 0; i < num; i++) {
                    if (wallY + 20 * i >= 599)
                        break;
                    wall.add(new Point(wallX, wallY + 20 * i));
                }
            else
                for (int i = 0; i < num; i++) {
                    if (wallX + 20 * i >= 599)
                        break;
                    wall.add(new Point(wallX + 20 * i, wallY));
                }
        }
    }
    void createSnake(LinkedList<Point> snake){
        snake.clear();
        while(true) {
            Boolean aJd=true;
            int x1 = rd.nextInt(579)+20;
            x1 = x1 - (x1 % 20);
            int y1 = rd.nextInt(599);
            y1 = y1 - (y1 % 20);
            Point pointH=new Point(x1,y1);
            Point pointT=new Point(x1-20,y1);
            Iterator<Point>a=wall.iterator();
            while(a.hasNext()) {
                Point temp=a.next();
                if (temp.equals(pointH) ||temp.equals(pointT)) {
                    aJd = false;
                    break;
                }
            }
            if(aJd) {
                snake.add(pointH);
                snake.add(pointT);
                break;
            }
        }
    }
    void createFood(){
        food=true;
        while(true) {
            Boolean aJd=true;
            int x1 = rd.nextInt(599);
            x1 = x1 - (x1 % 20);
            int y1 = rd.nextInt(599);
            y1 = y1 - (y1 % 20);
            pointFoodA=new Point(x1,y1);
            x1 = rd.nextInt(599);
            x1 = x1 - (x1 % 20);
            y1 = rd.nextInt(599);
            y1 = y1 - (y1 % 20);
            pointFoodB=new Point(x1,y1);
            Iterator<Point>a=wall.iterator();
            while(a.hasNext()) {
                Point temp=a.next();
                if (temp.equals(pointFoodA)||temp.equals(pointFoodB)){
                    aJd = false;
                    break;
                }
            }
            if(aJd)
                break;
        }
    }
    void eatFoodA(){
        if(snakeA.get(0).equals(pointFoodA)||snakeA.get(0).equals(pointFoodB)) {
            System.out.println("eatflag");
            Point temp=snakeA.get(snakeA.size()-2);
            Point tail=snakeA.get(snakeA.size()-1);
            Point newTail;
            if(temp.x==tail.x)
                newTail=new Point(temp.x,2*tail.y-temp.y);
            else
                newTail=new Point(2*tail.x-temp.x,temp.y);
            snakeA.add(newTail);
            scoreA+=1;
            As.setText(""+scoreA);
        }
        if(snakeA.get(0).equals(pointFoodA))
            pointFoodA=null;
        else if(snakeA.get(0).equals(pointFoodB))
            pointFoodB=null;
    }
    void eatFoodB(){
        if(snakeB.get(0).equals(pointFoodA)||snakeB.get(0).equals(pointFoodB)) {
            System.out.println("eatflag");
            Point temp=snakeB.get(snakeB.size()-2);
            Point tail=snakeB.get(snakeB.size()-1);
            Point newTail;
            if(temp.x==tail.x)
                newTail=new Point(temp.x,2*tail.y-temp.y);
            else
                newTail=new Point(2*tail.x-temp.x,temp.y);
            snakeB.add(newTail);
            scoreB+=1;
            Bs.setText(""+scoreB);
        }
        if(snakeB.get(0).equals(pointFoodA))
            pointFoodA=null;
        else if(snakeB.get(0).equals(pointFoodB))
            pointFoodB=null;
    }
    Boolean hitWall(LinkedList<Point> snake){
        ListIterator<Point>a=wall.listIterator();
        while(a.hasNext()){
            Point temp=a.next();
            if(temp.equals(snake.get(0)))
                return true;
        }
        return false;
    }
    Boolean hitSnakeA(){
        ListIterator<Point>a=snakeA.listIterator();
        ListIterator<Point>b=snakeB.listIterator();
        a.next();
        while(a.hasNext()){
            Point temp=a.next();
            if(temp.equals(snakeA.get(0)))
                return true;
        }
        while(b.hasNext()){
            Point temp=b.next();
            if(temp.equals(snakeA.get(0)))
                return true;
        }
        return false;
    }
    Boolean hitSnakeB(){
        ListIterator<Point>a=snakeA.listIterator();
        ListIterator<Point>b=snakeB.listIterator();
        b.next();
        while(a.hasNext()){
            Point temp=a.next();
            if(temp.equals(snakeB.get(0)))
                return true;
        }
        while(b.hasNext()){
            Point temp=b.next();
            if(temp.equals(snakeB.get(0)))
                return true;
        }
        return false;
    }
    void recordSort(){
        ArrayList<String>alist=new ArrayList();
        try{
            Scanner sc=new Scanner(f);
            while(sc.hasNextLine())
                alist.add(sc.nextLine());
            sc.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
        alist.sort(new Comparator<String>() {
            public int compare(String a, String b) {
                if (a.compareTo(b)>0)
                    return -1;
                else if(a.compareTo(b) == 0)
                    return 0;
                else
                    return 1;
            }
        });
        try{
            PrintWriter pwRe=new PrintWriter(f);
            Iterator<String>al=alist.iterator();
            while(al.hasNext())
                pwRe.println(al.next());
            pwRe.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    void readRecord(){
        JDialog Record=new JDialog();
        JPanel panel=new JPanel();
        panel.setOpaque(false);
        Record.setTitle("龙虎榜");
        Record.setSize(250,250);
        Record.setModal(true);
        Record.setLocationRelativeTo(app);
        panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
        JLabel []L={new JLabel(""),new JLabel(""),new JLabel(""),new JLabel(""),new JLabel("")};
        Record.setContentPane(panel);
        try{
            int i=0;
            Scanner sc=new Scanner(f);
            while(sc.hasNextLine()&&i<5) {
                System.out.println("^_^^_^^_^"+L[i].getText());
                L[i].setText(sc.nextLine());
                i++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        for(int i=0;i<5;i++)
            panel.add(L[i]);
        Record.setVisible(true);
    }
    public void paintComponent(Graphics gs){
        Graphics2D g= (Graphics2D)gs;
        super.paintComponent(gs);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);
        java.net.URL imgURL1 = RetroSnakes.class.getResource("1.jpg");
        Image image = Toolkit.getDefaultToolkit().getImage(imgURL1);
        g.drawImage(image,0,0,600,600,this);
        g.setPaint(new GradientPaint(115,135,Color.GREEN,230,135,Color.ORANGE,true));
        Iterator<Point>a=wall.listIterator();
        while(a.hasNext()) {
            Point temp=a.next();
            g.fillRoundRect(temp.x, temp.y, 20, 20, 10, 10);
        }
        g.setPaint(new GradientPaint(115,135,Color.BLUE,230,135,Color.blue,true));
        Iterator<Point>b=snakeA.listIterator();
        while(b.hasNext()) {
            Point temp=b.next();
            g.fillRoundRect(temp.x, temp.y, 20, 20, 10, 10);
        }
        g.setPaint(new GradientPaint(115,135,Color.CYAN,230,135,Color.cyan,true));
        b=snakeB.listIterator();
        while(b.hasNext()) {
            Point temp=b.next();
            g.fillRoundRect(temp.x, temp.y, 20, 20, 10, 10);
        }
        g.setPaint(new GradientPaint(115,135,Color.RED,230,135,Color.PINK,true));
        if(pointFoodA!=null)
            g.fillRoundRect(pointFoodA.x, pointFoodA.y, 20, 20, 10, 10);
        if(pointFoodB!=null)
            g.fillRoundRect(pointFoodB.x, pointFoodB.y, 20, 20, 10, 10);
    }
    public static void main(String[] args) {
        inputIP inputip=new inputIP();
        RetroSnakes t = new RetroSnakes();
        app = new JFrame();
        JMenuBar menuBar = new JMenuBar();
        JMenu menu1 = new JMenu("控制");
        JMenu menu2 = new JMenu("速度");
        JMenuItem item1 = new JMenuItem("开始");
        JMenuItem item2 = new JMenuItem("暂停");
        JMenuItem item3 = new JMenuItem("继续");
        JMenuItem item4 = new JMenuItem("慢");
        JMenuItem item5 = new JMenuItem("中");
        JMenuItem item6 = new JMenuItem("快");
        JMenuItem item7=new JMenuItem("龙虎榜");
        app.setJMenuBar(menuBar);
        menuBar.add(menu1);
        menu1.add(item1);
        menu1.add(item2);
        menu1.add(item3);
        menuBar.add(menu2);
        menu2.add(item4);
        menu2.add(item5);
        menu2.add(item6);
        menuBar.add(item7);
        app.setTitle("贪吃蛇");
        app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        app.setSize(605,650);
        app.setResizable(false);
        app.setLocationRelativeTo(null);
        app.add(t);
        app.setVisible(true);
        item7.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                t.readRecord();
            }
        });
        item1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.startFlag = true;
                try {
                    dosOutToServer.writeBytes("forceS\n");
                    dosOutToServer.writeBytes(t.startFlag.toString() + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        item2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.startFlag = false;
                try {
                    dosOutToServer.writeBytes("forceS\n");
                    dosOutToServer.writeBytes(t.startFlag.toString() + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        item3.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.startFlag = true;
                try {
                    dosOutToServer.writeBytes("forceS\n");
                    dosOutToServer.writeBytes(t.startFlag.toString() + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        item4.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.millis = 700l;
                try {
                    dosOutToServer.writeBytes("forceM\n");
                    dosOutToServer.writeBytes("" + t.millis + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        item5.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.millis = 300l;
                try {
                    dosOutToServer.writeBytes("forceM\n");
                    dosOutToServer.writeBytes("" + t.millis + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        item6.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                t.millis = 100l;
                try {
                    dosOutToServer.writeBytes("forceM\n");
                    dosOutToServer.writeBytes("" + t.millis + '\n');
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        t.startGame();
        playMusic();
    }
    static void playMusic(){//背景音乐播放
        try {
            java.net.URL cb = RetroSnakes.class.getResource("2.wav");
            AudioClip aau;
            aau = Applet.newAudioClip(cb);
            aau.play();
            aau.loop();//循环播放

        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}
